/*
* ============================================================================
*  Name        : sea_list.h
*  Part of     : Finite state machine utilities
*  Description : list definition
*  Version     : %version: %
*  
*
* ============================================================================
*/
#if !defined( __sea_list_h__ )
#define __sea_list_h__

#include "sea_platform.h"

/**
 * @file sea_list.h
 * @brief 
 * @ref sea::List
 *
 * @ingroup AssociationUtilities
 */
namespace sea
{
    class Object;

    /** 
     * @class List sea_list.h "sea_list.h"
     * @brief List implementation. \b Thread \b safe. Keeps track of list properties<br>. 
     * Links a number of sea objects by specified association.
     * @li number of elements
     * @li first and last elements.
     *
     * @ingroup AssociationUtilities
     */
    class List: public Object
    {
    public:
        /**
         * Contructor
         * @param id     association Id
         */
        List( Association id ):
            m_size( 0 ),
            m_id( ( id.is_enum_object( ) && !id.get_enum_object( ).m_object ) ? 
                    Association( 0, this ) : id ) { }

        List( ):
            m_size( 0 ),
            m_id( this ) { }

        ~List( ) { clear( ); }

        /**
         * Attach as a first object in the list
         *
         * @param obj Pointer to an object
         * @param unique If true, it is unique association
         *
         * @return @li TRUE     if object Listed successfully
         * @return @li FALSE    otherwise.
         *                      1. Inserted object is NULL
         *                      2. Attachement failed. See Object::AttachLeftFrom
         */
        virtual bool attach_first( Object* obj, bool unique = false );
        virtual bool attach_first( ref< >& obj, bool unique = false ){ return attach_first( obj.get( ), unique ); }
        virtual bool attach_first( ref< List >& obj, bool unique = false ){ return attach_first( obj.get( ), unique ); }

        /**
         * Attach as a last object in the list
         *
         * @param obj Pointer to an object
         * @param unique If true, it is unique association
         *
         * @return @li TRUE     if object Listed successfully
         * @return @li FALSE    otherwise.
         *                      1. Inserted object is NULL
         *                      2. Attachement failed. See Object::AttachRightFrom
         */
        virtual bool attach_last( Object* obj, bool unique = false );
        virtual bool attach_last( ref< >& obj, bool unique = false ){ return attach_last( obj.get( ), unique ); }
        virtual bool attach_last( ref< List >& obj, bool unique = false ){ return attach_last( obj.get( ), unique ); }

        /**
         * Attach new_obj on the RIGHT/LEFT of existing in the list obj.Pay attention to 
         * the parameters placement
         *
         * @param new_obj Pointer to an object to be attached 
         * @param obj Pointer to an object in the list
         *
         * @return @li TRUE     if object Listed successfully
         * @return @li FALSE    otherwise.
         *                      1. Inserted object is NULL
         *                      2. Attachement failed. See Object::AttachRightFrom, Object::AttachLeftFrom
         */
        bool attach_right_of( Object* obj, Object* new_obj );
        bool attach_right_of( ref< >& obj, ref< >& new_obj ){ return attach_right_of( obj.get( ), new_obj.get( ) ); }
        bool attach_right_of( ref< List >& obj, ref< >& new_obj ){ return attach_right_of( obj.get( ), new_obj.get( ) ); }
        bool attach_left_of( Object* new_obj, Object* obj );
        bool attach_left_of( ref< >& new_obj, ref< >& obj ){ return attach_left_of( obj.get( ), new_obj.get( ) ); }
        bool attach_left_of( ref< List >& new_obj, ref< >& obj ){ return attach_left_of( obj.get( ), new_obj.get( ) ); }

        /**
         * Insert new_obj on the RIGHT/LEFT of existing in the list obj. Pay attention to 
         * the parameters placement
         *
         * @param new_obj Pointer to an object to be inserted 
         * @param obj Pointer to an object in the list
         *
         * @return @li TRUE     if object Listed successfully
         * @return @li FALSE    otherwise.
         *                      1. Inserted object is NULL
         *                      2. Attachement failed. See Object::InsertRightFrom, Object::InsertLeftFrom
         */
        bool insert_right_of( Object* obj, Object* new_obj );
        bool insert_right_of( ref< >& obj, ref< >& new_obj ){ return insert_right_of( obj.get( ), new_obj.get( ) ); }
        bool insert_right_of( ref< List >& obj, ref< >& new_obj ){ return insert_right_of( obj.get( ), new_obj.get( ) ); }
        bool insert_left_of( Object* new_obj, Object* obj );
        bool insert_left_of( ref< >& new_obj, ref< >& obj ){ return insert_left_of( obj.get( ), new_obj.get( ) ); }
        bool insert_left_of( ref< List >& new_obj, ref< >& obj ){ return insert_left_of( obj.get( ), new_obj.get( ) ); }

        /**
         * Gets first element in the list
         * 
         * @return first element in the list
         */
        virtual sea::aref get_first( ) { return m_first; }

        /**
         * Gets last element in the list
         * 
         * @return first element in the list
         */
        virtual sea::aref get_last( ) { return m_last; }

        /**
         * Remove object from the list
         *
         * @param obj Pointer to an object
         *
         * @return @li TRUE     if object Listed successfully
         * @return @li FALSE    otherwise.
         *                      1. Inserted object is NULL
         *                      2. detach failed. See Object::detach
         */
        virtual bool detach( Object* obj );
        virtual bool detach( ref< >& obj ){ return detach( obj.get( ) ); }
        virtual bool detach( ref< List >& obj ){ return detach( obj.get( ) ); }

        /**
         * Remove all objects from the list
         */
        virtual void clear( );

        /**
         * Get number of elements in the list
         * 
         * @return number of elements in the list
         */
        virtual int size( ){ return m_size; }

        /**
         * Get reference to the list's association id
         * 
         * @return reference to association
         */
        Association& id( ) { return m_id; }

        /**
         * Get lock for atomic operations on the list
         * 
         * @return reference to association
         */
        OsMutex* lock( ) { return &m_lock; }

    private:
        sea::aref m_first;
        sea::aref m_last;
        int m_size;
        Association m_id;
        OsMutex m_lock;
    };
}

#endif
